from typing import List

from ioservice.alumni.alumni import search_alumni_by_query
from ioservice.activity import find_activities_by_query, count_activities, aggregate_activities
from ioservice.activity_register import find_register_records_by_query, count_register_records
from ioservice.institution import get_institution_by_id
from ioservice.common.mongo import aggregate_models
from ioservice.const import activity_col, institution_col
from ioservice.common.mongo import count_documents as mongo_count_docs
from models.common import OID
from models.fileserver import FileEntity
from utils.iterutil import generate_batch
from bson import ObjectId
from models.activity import Activity
from models.institution import Institution
from models.alumni.alumni import Alumni
from models.common import MongoModel
from datetime import datetime
from typing import Optional
from pydantic import Field


class ActiveInstitution(Activity):
    id: Optional[OID] = Field(title="机构ID")
    activity_name: Optional[str] = Field(title="活动名称")
    activity_images: Optional[List[FileEntity]] = Field(title="活动图片")
    start_time: Optional[datetime] = Field(title="活动开始时间")
    institution_info: Optional[Institution] = Field(title="机构信息")
    alumni: Optional[List[Alumni]] = Field(title="校友信息")


class InstitutionWithActivity(Institution):
    activity: Optional[Activity]
    alumni: Optional[List[Alumni]]


async def get_institution_activities(institution_id, **kwargs):
    total = await count_activities({"institution_id": ObjectId(institution_id)})
    activities = await find_activities_by_query({"institution_id": ObjectId(institution_id)}, **kwargs)
    return total, activities


async def get_recent_active_institutions():
    piplines = [
        {"$match": {"start_time": {"$exists": True, "$ne": None}, "is_deleted": {"$ne": True}}},
        {"$sort": {"start_time": -1}},
        {
            "$lookup": {
                "from": "activity_register",
                "localField": "_id",
                "foreignField": "activity_id",
                "as": "registered"
            }
        },
        {
            "$lookup": {
                "from": "alumni",
                "localField": "registered.person_id",
                "foreignField": "_id",
                "pipeline": [{"$limit": 10}],
                "as": "alumni"
            }
        },
        {
            "$lookup": {
                "from": "institution",
                "localField": "institution_id",
                "foreignField": "_id",
                "as": "institution_info"
            }
        },
        {
            "$unwind": "$institution_info"
        },
        {
            "$group": {
                "_id": "$institution_info._id",
                "activity_name": {"$first": "$name"},
                "activity_images": {"$first": "$images"},
                "start_time": {"$first": "$start_time"},
                "institution_info": {"$first": "$institution_info"},
                "alumni": {"$first": "$alumni"}
            }
        },
        {"$sort": {"start_time": -1}},
        {
            "$limit": 10
        }
    ]
    institutions = await aggregate_models(activity_col, piplines, ActiveInstitution)
    for institution in institutions:
        institution.institution_info.id = institution.id
        if institution.alumni:
            for alumni in institution.alumni:
                if alumni.images:
                    for image in alumni.images:
                        image.fill_url()
    return institutions


async def get_target_active_institutions():
    piplines = [
        {
            "$match": {
                "institution_name": {"$in": ["科技人才服务处", "教育培训服务处", "评价和奖励服务处", "综合处"]}, "is_deleted": {"$ne": True}
            }
        },
        {
            "$lookup": {
                "from": "activity",
                "localField": "_id",
                "foreignField": "institution_id",
                "pipeline": [{"$match": {"is_deleted": {"$ne": True}}}, {"$sort": {"start_time": -1}}, {"$limit": 1}],
                "as": "activity"
            }
        },
        {
            "$unwind": "$activity"
        },
        {
            "$lookup": {
                "from": "activity_register",
                "localField": "activity._id",
                "foreignField": "activity_id",
                "pipeline": [{"$match": {"is_deleted": {"$ne": True}}}],
                "as": "registered"
            }
        },
        {
            "$lookup": {
                "from": "alumni",
                "localField": "registered.person_id",
                "foreignField": "_id",
                "pipeline": [{"$match": {"is_deleted": {"$ne": True}}}, {"$project":{"alumni_score":True,"name":True,"name_zh":True}}, {"$sort": {"alumni_score": -1}}, {"$limit": 5}],
                "as": "alumni"
            }
        },
        {
            "$project": {
                "registered": False
            }
        }
    ]
    institutions = await aggregate_models(institution_col, piplines, InstitutionWithActivity)
    for institution in institutions:
        if institution.activity and institution.activity.images:
            for image in institution.activity.images:
                image.fill_url()
    return institutions


async def get_alumni_by_activities(activities: List[OID], **kwargs):
    query = {"activity_id": {'$in': activities}}
    total = await count_register_records(query)
    records = []
    for i in range(0, total, 50):
        cur_records = await find_register_records_by_query(query, fields=["person_id"], offset=i, size=50)
        records.extend(cur_records)
    person_ids = [record.person_id for record in records]
    total, alumni = await search_alumni_by_query({"_id": {'$in': person_ids}}, **kwargs)
    return total, alumni


async def get_institution_activities_alumni(institution_id, **kwargs):
    total, _ = await get_institution_activities(institution_id, offset=0, size=1)
    activities = []
    for i in range(0, total, 50):
        _, cur_activities = await get_institution_activities(institution_id, offset=i, size=50)
        activities.extend(cur_activities)
    activities_ids = [activity.id for activity in activities]
    res = await get_alumni_by_activities(activities_ids, **kwargs)
    return res
